package com.sinszm.es.parser;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.util.StrUtil;
import com.sinszm.common.exception.ApiException;
import com.sinszm.common.util.CamelAndUnderLineConverter;
import com.sinszm.common.util.CommonUtils;
import com.sinszm.es.annotation.Document;
import com.sinszm.es.annotation.Id;

import java.lang.reflect.Field;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;

/**
 * 实体解析器
 *
 * @author sinszm
 */
public final class DomainUtil {

    /**
     * 获取实体的索引名称
     * @param tClass    实体类
     * @param <T>       泛型
     * @return          索引名称
     */
    public static <T> String indexName(Class<T> tClass) {
        if (tClass == null) {
            throw new ApiException("实体类不能为空");
        }
        Document document = AnnotationUtil.getAnnotation(tClass,Document.class);
        if (document == null) {
            throw new ApiException("实体类缺失Document注解");
        }
        String name = CommonUtils.isEmpty(document.value()) ? CamelAndUnderLineConverter.humpToLine(
                tClass.getSimpleName()
        ) : document.value();
        return StrUtil.startWith(name, "_") ? name.substring(1) : name;
    }

    /**
     * 获取实体的字段索引配置
     * @param tClass    实体类
     * @param <T>       泛型
     * @return          字段属性配置
     */
    public static <T> Map<String,Object> fieldName(Class<T> tClass) {
        if (tClass == null) {
            throw new ApiException("实体类不能为空");
        }
        Map<String, Object> properties = new HashMap<>(0);
        for (Field f : tClass.getDeclaredFields()) {
            com.sinszm.es.annotation.Field field = AnnotationUtil.getAnnotation(f,
                    com.sinszm.es.annotation.Field.class);
            if (field != null) {
                Map<String, Object> map = new HashMap<>(0);
                map.put("type", field.type().name().toLowerCase());
                if (field.store()) {
                    map.put("store", true);
                }
                if (!CommonUtils.isEmpty(field.searchAnalyzer())) {
                    map.put("search_analyzer", field.searchAnalyzer());
                }
                if (!CommonUtils.isEmpty(field.analyzer())) {
                    map.put("analyzer", field.analyzer());
                }
                if (Date.class.equals(f.getType())) {
                    if (!CommonUtils.isEmpty(field.format())) {
                        map.put("format", field.format());
                    } else {
                        map.put("format", "strict_date_time");
                    }
                }
                //字段存入
                String name = CommonUtils.isEmpty(field.name()) ? CamelAndUnderLineConverter.humpToLine(
                        f.getName()
                ) : field.name();
                properties.put(name, map);
            }
        }
        //属性组合并创建索引结构
        Map<String, Object> mapping = new HashMap<>(0);
        mapping.put("properties", properties);
        return mapping;
    }

    /**
     * 获取数据中主键注解的字段值
     *
     * @param data  数据对象
     * @param <T>   泛型
     * @return      主键值
     */
    private static <T> Object primaryValue(T data) {
        if (data == null) {
            throw new ApiException("数据不能为空");
        }
        return Stream.of(data.getClass().getDeclaredFields())
                .filter(field -> AnnotationUtil.hasAnnotation(field, Id.class))
                .map(field -> {
                    field.setAccessible(true);
                    try {
                        return field.get(data);
                    } catch (IllegalAccessException e) {
                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .findFirst().orElseThrow(() -> new ApiException("缺失有效主键注解字段"));
    }

    /**
     * 获取数据中主键注解的字段值
     *
     * @param data  数据对象
     * @param <T>   泛型
     * @return      主键值
     */
    public static <T> String idValue(T data) {
        return String.valueOf(primaryValue(data));
    }

    /**
     * 转换实体类中的数据到map中
     * @param data  数据对象
     * @param <T>   泛型
     * @return      map数据
     */
    public static <T> Map<String,Object> fieldValue(T data) {
        if (data == null) {
            throw new ApiException("数据不能为空");
        }
        Map<String, Object> params = new HashMap<>(0);
        for (Field f : data.getClass().getDeclaredFields()) {
            com.sinszm.es.annotation.Field field = AnnotationUtil.getAnnotation(f,
                    com.sinszm.es.annotation.Field.class);
            if (field != null) {
                f.setAccessible(true);
                String name = CommonUtils.isEmpty(field.name()) ? CamelAndUnderLineConverter.humpToLine(
                        f.getName()
                ) : field.name();
                try {
                    params.put(name, f.get(data));
                } catch (IllegalAccessException e) {
                    e.printStackTrace(System.err);
                }
            }
        }
        return params;
    }

}